//
// CrackAdmin
//
// Copyright (C) jextra.net.
//
//  This file is part of the Crack build system.
//
//  The Crack build system is free software; you can redistribute it 
//  and/or modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  The Crack build system is distributed in the hope that it will be 
//  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with the Crack build system; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
//  02111-1307 USA.
//

package net.jextra.crack.core;

import java.util.*;
import net.jextra.crack.*;

/**
 * <p>
 * This is the singleton with a "main" method in it that responds to the "crackadmin" script.
 * </p>
 */
public class CrackAdmin extends CrackApp
{
    // ============================================================
    // Fields
    // ============================================================

    public static final String CMD_UPDATE_LIB = "updateLib";
    public static final String CMD_UPDATE_CONF = "updateConf";
    public static final String CMD_VERSION = "version";

    private static CrackAdmin _instance;

    private HashMap<String, CrackConfCommand> commands;
    private boolean verbose;

    // ============================================================
    // Constructors
    // ============================================================

    public CrackAdmin()
        throws Exception
    {
        commands = new HashMap<String, CrackConfCommand>();
        addCommand( new HelpCommand() );
        addCommand( new UpdateConfCommand() );
        addCommand( new UpdateLibCommand() );
        addCommand( new VersionCommand() );

        verbose = false;
    }

    // ============================================================
    // Methods
    // ============================================================

    // ----------
    // public
    // ----------

    public static void main( String[] args )
    {
        try
        {
            _instance = new CrackAdmin();
            _instance.execute( args );
        }
        catch ( CrackError ex )
        {
            if ( _instance.verbose )
            {
                ex.printStackTrace();
            }
            else
            {
                ex.print();
            }
        }
        catch ( Throwable ex )
        {
            ex.printStackTrace();
        }
    }

    public static CrackAdmin getInstance()
    {
        return _instance;
    }

    public void execute( String[] args )
        throws Exception
    {
        verifyCrackHome();

        List<String> commands = parseArgs( args );
        if ( commands == null )
        {
            return;
        }

        // Default is to print admin help
        if ( commands.size() == 0 )
        {
            printHelp();
            return;
        }

        long now = System.currentTimeMillis();
        for ( String command : commands )
        {
            invokeCommand( command );
        }
        long sec = System.currentTimeMillis() - now;
        sec /= 1000;
        System.out.printf( "\n(Total time: %d seconds)\n", sec );
    }

    // ----------
    // private
    // ----------

    private void addCommand( CrackConfCommand command )
    {
        commands.put( command.getName(), command );
    }

    private List<String> parseArgs( String[] args )
    {
        ArrayList<String> commands = new ArrayList<String>();
        for ( int i = 0; i < args.length; i++ )
        {
            if ( args[i].equals( "-verbose" ) )
            {
                verbose = true;
            }
            else
            {
                commands.add( args[i] );
            }
        }

        return commands;
    }

    private void printHelp()
    {
        System.out.println();
        System.out.println( "Usage: crackadmin [options] command." );
        System.out.println();
        System.out.println( "Options:" );
        System.out.println();
        System.out.println( "  -verbose Output verbose errors." );
        System.out.println();
        System.out.println( "Commands:" );
        System.out.println();

        int maxLength = 0;
        ArrayList<String> commandNames = new ArrayList<String>();
        for ( String commandName : commands.keySet() )
        {
            commandNames.add( commandName );
            if ( commandName.length() > maxLength )
            {
                maxLength = commandName.length();
            }
        }

        Collections.sort( commandNames );

        for ( String commandName : commandNames )
        {
            System.out.printf( "  %-" + maxLength + "s  %s\n", commandName, commands.get( commandName )
                .getDescription() );
        }
    }

    private void invokeCommand( String commandName )
        throws Exception
    {
        CrackConfCommand command = commands.get( commandName );
        if ( command != null )
        {
            System.out.println();
            System.out.println( PRIMARY_HEADER );
            System.out.printf( PRIMARY_HEADER_FORMAT, commandName );
            System.out.println( PRIMARY_HEADER );
            System.out.println();

            command.execute();
        }
        else
        {
            throw new CrackError( "Unknown command '%s'.", commandName );
        }
    }

    private void updateConf()
        throws Exception
    {
        CrackSelfUpdater updater = new CrackSelfUpdater( CrackContext.getInstance().getUpdater() );
        updater.execute( CrackContext.getInstance().getConfDir(), "conf" );
    }

    private void updateLib()
        throws Exception
    {
        CrackSelfUpdater updater = new CrackSelfUpdater( CrackContext.getInstance().getUpdater() );
        updater.execute( CrackContext.getInstance().getLibDir(), "lib" );
    }

    // ============================================================
    // Inner Classes
    // ============================================================

    public interface CrackConfCommand
    {
        public String getName();

        public String getDescription();

        public boolean execute()
            throws Exception;
    }

    private class HelpCommand implements CrackConfCommand
    {
        @Override
        public String getName()
        {
            return CMD_HELP;
        }

        @Override
        public String getDescription()
        {
            return "Display this help.";
        }

        @Override
        public boolean execute()
            throws Exception
        {
            printHelp();
            return true;
        }
    }

    private class VersionCommand implements CrackConfCommand
    {
        @Override
        public String getName()
        {
            return CMD_VERSION;
        }

        @Override
        public String getDescription()
        {
            return "Output Crack version.";
        }

        @Override
        public boolean execute()
            throws Exception
        {
            printCrackVersion();
            return true;
        }
    }

    private class UpdateConfCommand implements CrackConfCommand
    {
        @Override
        public String getName()
        {
            return CMD_UPDATE_CONF;
        }

        @Override
        public String getDescription()
        {
            return "Compare dates and download any newer conf files from the Crack Updater/s.";
        }

        @Override
        public boolean execute()
            throws Exception
        {
            updateConf();
            return true;
        }
    }

    private class UpdateLibCommand implements CrackConfCommand
    {
        @Override
        public String getName()
        {
            return CMD_UPDATE_LIB;
        }

        @Override
        public String getDescription()
        {
            return "Compare dates and download any newer lib files from the Crack Updater/s.";
        }

        @Override
        public boolean execute()
            throws Exception
        {
            updateLib();
            return true;
        }
    }
}
